/* LEDC (LED Controller) basic example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "esp_err.h"
#include "driver/ledc.h"
#include "my_fans_drv.h"

/********************
 * 系统一共有4个timer，每个timer有6个通道
 * **/
#define FANS_SPEED_MODE         LEDC_LOW_SPEED_MODE
#define FANS_DUTY_RES           LEDC_TIMER_10_BIT       // Set duty resolution to 13 bits
#define FANS_DEFAULT_FREQ       (30000)                 // Frequency in Hertz. Set frequency at 4 kHz

#define FANS_TIMER              LEDC_TIMER_2
#define FANS_GPIO               (GPIO_NUM_6)           // Define the output GPIO   实际板子使用的是GPIO6  
#define FANS_PWM_CHANNEL        LEDC_CHANNEL_3
#define FANS_DEFAULT_DUTY       (512)                   // Set duty to 25%. (2 ** 10) * 25% = 256

static const char *TAG = "fans";
//队列句柄
QueueHandle_t fans_msg_queue;

typedef struct
{
    ledc_timer_config_t timer;
    ledc_channel_config_t channel;
}fans_param_t;


fans_param_t fans_data;

/* Warning:
 * For ESP32, ESP32S2, ESP32S3, ESP32C3, ESP32C2, ESP32C6, ESP32H2, ESP32P4 targets,
 * when FANS_SPEED_MODE selects the maximum duty resolution (i.e. value equal to SOC_LEDC_TIMER_BIT_WIDTH),
 * 100% duty cycle is not reachable (duty cannot be set to (2 ** SOC_LEDC_TIMER_BIT_WIDTH)).
 */

static void fans_timer_init(void)
{
    // PWM timer configuration
    fans_data.timer.speed_mode = FANS_SPEED_MODE;
    fans_data.timer.duty_resolution = FANS_DUTY_RES;
    fans_data.timer.timer_num = FANS_TIMER;
    fans_data.timer.freq_hz = FANS_DEFAULT_FREQ; // Set output frequency at 4 kHz
    fans_data.timer.clk_cfg = LEDC_AUTO_CLK;
    ESP_ERROR_CHECK(ledc_timer_config(&fans_data.timer));

    // PWM channel configuration
    fans_data.channel.speed_mode = FANS_SPEED_MODE;
    fans_data.channel.channel = FANS_PWM_CHANNEL;
    fans_data.channel.timer_sel = FANS_TIMER;
    fans_data.channel.intr_type = LEDC_INTR_DISABLE;
    fans_data.channel.gpio_num = FANS_GPIO;
    fans_data.channel.duty = 0; // Set duty to 0%
    fans_data.channel.hpoint = 0;  
    ESP_ERROR_CHECK(ledc_channel_config(&fans_data.channel));
}

/*************************************************************
 * 风扇 占空比调节:1%~100%
 * 
**********************************************************/
void fans_pwm_update(uint32_t freq, uint8_t duty)
{
    // int max_duty;
    int period = 1024, cur_freq;

    if(duty > 100){
        printf("%s, duty err[%d] \r\n", __func__, duty);
        return;
    }

    cur_freq = freq;
    if((freq > 100000) || (freq < 20000)){
        cur_freq = 30000;
    }

    if(cur_freq > 78000){
        fans_data.timer.duty_resolution = LEDC_TIMER_9_BIT;
        period = 512;
    }
    else if(cur_freq > 39000){
        fans_data.timer.duty_resolution = LEDC_TIMER_10_BIT;
        period = 1024;
    }
    else{
        fans_data.timer.duty_resolution = LEDC_TIMER_11_BIT;
        period = 2048;
    } 

    ESP_ERROR_CHECK(ledc_timer_config(&fans_data.timer));
    ESP_ERROR_CHECK(ledc_set_freq(FANS_SPEED_MODE, fans_data.timer.timer_num, cur_freq));
    // 占空比 50%
    ESP_ERROR_CHECK(ledc_set_duty(FANS_SPEED_MODE, FANS_PWM_CHANNEL, period*duty/100));
    ESP_ERROR_CHECK(ledc_update_duty(FANS_SPEED_MODE, FANS_PWM_CHANNEL));
}

/*************************************
 * 测试程序 ,占空比和频率一直变化
**************************************/
static void fans_test_breath(void)
{
    // static int freq;
    static int duty;

    // freq += 1000;
    duty += 10;
    duty %= 100;

    // 固定100k hz
    fans_pwm_update(10000, duty);
}

/*************************************************************
 * fans_handler_task
 * PWM 反向控制风扇转速
 *      占空比越低，风扇转速越快， 占空比越高，风扇转速越低
**************************************************************/
static void fans_handler_task(void *arg)
{
    uint8_t duty = 0;
    (void) arg; //Unused
    fans_msg_t fans_msg;
    while (1) {
        /* Waiting for touch element messages */
        if(xQueueReceive(fans_msg_queue, &(fans_msg), portMAX_DELAY))
		{ 
            // fans_test_breath();
			ESP_LOGI(TAG, "fans queue recv_level[%d] \r\n", fans_msg.level);
            switch(fans_msg.level){
                case LEVEL_0:   
                    duty = 100; 
                    break;
                case LEVEL_1:
                    duty = 75;
                    break;
                case LEVEL_2:
                    duty = 50;
                    break;
                case LEVEL_3:
                    duty = 10;
                    break;
                default:
                    duty = 0;
                    break;
            }
            fans_pwm_update(FANS_DEFAULT_FREQ, duty);
		}
    }
}

/*************************************
 *暂时用 30khz， 50%占空比（默认开启）
**************************************/
void my_fans_init(void)
{
    int ret = 0;

    fans_timer_init();

    ESP_ERROR_CHECK(ledc_set_duty(FANS_SPEED_MODE, FANS_PWM_CHANNEL, FANS_DEFAULT_DUTY));
    ESP_ERROR_CHECK(ledc_update_duty(FANS_SPEED_MODE, FANS_PWM_CHANNEL));

    fans_msg_queue = xQueueCreate(10, sizeof(fans_msg_t));
    //创建队列返回已创建队列的句柄
	if(fans_msg_queue == NULL){ 
        ESP_LOGE(TAG, "failed to create queue1= %p \n", fans_msg_queue);
        return;
	}
    ret = xTaskCreate(&fans_handler_task, "fans_handler_task", 2 * 1024, NULL, 5, NULL);
    
    if(ret == 0){
        ESP_LOGE(TAG, "creat fans_handler_task err!!");
		return;
    }
	ESP_LOGI(TAG, "my_fans_init succ");
}
